import { animation, AnimationClip, Sprite, SpriteFrame } from "cc";
import ResourceManager from "../Runtime/ResourceManager";
import { ANIMATION_SPEED } from "../utils/constant";
import { StateMachine } from "./StateMachine";
import { sortSpriteFrame } from "../utils";


/**
 * 状态基类
 * 1.需要知道要播放的animationClip
 * 2.需要播放动画的能力
 */
export default class State {
  private animationClip: AnimationClip
  /**
   * @param fsm 状态机
   * @param path 组成动画的图片路径
   * @param wrapMode 动画播放模式，默认是Normal，播放一次
   * @param playSpeed 动画播放速度，默认是ANIMATION_SPEED
   * @param events 动画帧事件
   */
  constructor(
    private fsm: StateMachine,
    private path: string,
    private wrapMode: AnimationClip.WrapMode = AnimationClip.WrapMode.Normal,
    private playSpeed: number = ANIMATION_SPEED,
    private events: AnimationClip.IEvent[] = []
  ) {
    this.init()
  }

  async init() {

    const promise = ResourceManager.Instance.loadDir(this.path)
    // 加载资源是耗时任务，每次init放入等待列表,在PlayerStateMachine中确保所有资源加载完毕
    this.fsm.waitingList.push(promise)

    // 将资源转换为动画剪辑
    const spriteFrames = await promise
    // 由于资源请求加载，返回的顺序不固定，所以需要排序
    const frames: [number, SpriteFrame][] = sortSpriteFrame(spriteFrames).map((item, index) => {
      return [this.playSpeed * index, item]
    })

    // 创建一个对象轨道
    const track = new animation.ObjectTrack()
    track.path = new animation.TrackPath().toComponent(Sprite).toProperty('spriteFrame')
    track.channel.curve.assignSorted(frames)

    // 将轨道添加到动画剪辑以应用
    this.animationClip = new AnimationClip()
    this.animationClip.name = this.path  // 设置动画剪辑的名称
    this.animationClip.addTrack(track)
    this.animationClip.duration = frames.length * ANIMATION_SPEED  // 设置动画剪辑的周期
    this.animationClip.wrapMode = this.wrapMode // 设置动画剪辑的播放模式

    // 添加帧事件
    this.events.forEach(event => {
      this.animationClip.events.push(event)
    })
    // @ts-ignore 虽然 API 已废弃，但当前版本仍需要调用它来确保事件生效
    this.animationClip.updateEventDatas()
  }

  // 播放动画
  run() {
    // 如果将要播放的动画剪辑和当前动画剪辑相同，则不重新播放
    if(this.fsm.animationComponent?.defaultClip?.name === this.animationClip.name) return
    // 设置动画组件的默认动画剪辑
    this.fsm.animationComponent.defaultClip = this.animationClip
    // 播放动画
    this.fsm.animationComponent.play()
  }

}
